zygote的分裂

1 zygote的分裂

前面已经讲了zygote分裂出了长子system_server,然后SS(system_server)就通过initAndLoop进行消息循环处理了。那么谁会向zygote发送消息呢?这里以一个activity的启动为例,进行具体分析zygote的分裂和繁殖。

1.1  ActivityManagerService发送请求

ActivityManagerService也是SS创建的(在ServerThread里面)。假设通过startActivity来启动一个新的activity,而这个activity附属于一个还未启动的进程,那么这个进程该如何启动呢?先看看ActivityManagerService中的startProcessLocked函数:

这个函数很复杂,主要是判断启动activity的进程是否孤立进程,是否死亡等,并做好进程记录,放入processRecode类中~,核心部分在最后的函数调用startProcessLocked中。

startProcessLocked(ProcessRecord app,String hostingType, String hostingNameStr)的代码也比较多,这里就不详细列举了,只列出它完成的功能:

①设置pid并更新cpu状态。

②如果该进程不是孤立进程的话就通过PackageManager获取该进程对应的uid所对应的gid;否者直接跳到第四步。

③增加共享APP的 gid,这样的话,这些共享APP就可以想访问so库一样访问一些共享资源了。

④再设置该进程的一些属性——是否启用checkjni,安全模式之类的。

⑤然后调用Process.start("android.app.ActivityThread"……)来启动进程,这个函数要么正确执行并返回包含有新进程pid的结果,要么就失败抛出Runtime异常。这个process类是android提供的,并非jdk中的process类。

⑥最后就是一些不太重要的扫尾工作。

接下来看android.os.Process的start函数,详细代码在Process.java中:

public static final ProcessStartResult start(final String processClass,

final String niceName,int uid, int gid, int[] gids,int debugFlags, int mountExternal,

int targetSdkVersion,String seInfo,String[] zygoteArgs) {

        try {

//调用startViaZygote函数

            return startViaZygote(processClass, niceName, uid, gid, gids,

                    debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);

        } catch (ZygoteStartFailedEx ex) {

            Log.e(LOG_TAG,

                    "Starting VM process through Zygote failed");

            throw new RuntimeException(

                    "Starting VM process through Zygote failed", ex);

        }

  }

startViaZygote函数代码如下:

private static ProcessStartResult startViaZygote(final String processClass,

                                  final String niceName,

                                  final int uid, final int gid,

                                  final int[] gids,

                                  int debugFlags, int mountExternal,

                                  int targetSdkVersion,

                                  String seInfo,

                                  String[] extraArgs)

                                  throws ZygoteStartFailedEx {

        synchronized(Process.class) {

            ArrayList<String> argsForZygote = new ArrayList<String>();

 

            // --runtime-init, --setuid=, --setgid=,

            // and --setgroups= must go first

            argsForZygote.add("--runtime-init"); //这个参数很重要

            ……一些参数处理

           //最后调用zygoteSendArgsAndGetResult

            return zygoteSendArgsAndGetResult(argsForZygote);

        }

    }

zygoteSendArgsAndGetResult函数主要功能:向zygote进程发送一个参数列表,zygote进程会启动一个新的子进程并返回该子进程的pid号。详细代码如下:

private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args) throws ZygoteStartFailedEx {

//★这是关键函数!打开了同zygote进程的socket通信。

        openZygoteSocketIfNeeded();

        try {

            /**

             * See com.android.internal.os.ZygoteInit.readArgumentList()

             * Presently the wire format to the zygote process is:

             * a) a count of arguments (argc, in essence)

             * b) a number of newline-separated argument strings equal to count

             *

             * After the zygote process reads these it will write the pid of

             * the child or -1 on failure, followed by boolean to

             * indicate whether a wrapper process was used.

             */

            sZygoteWriter.write(Integer.toString(args.size()));

            sZygoteWriter.newLine();

            int sz = args.size();

            for (int i = 0; i < sz; i++) {

                String arg = args.get(i);

                if (arg.indexOf('\n') >= 0) {

                    throw new ZygoteStartFailedEx(

                            "embedded newlines not allowed");

                }

                sZygoteWriter.write(arg);

                sZygoteWriter.newLine();

            }

   //读取zygote处理完的结果,便可得到zygote返回的子进程的pid

            sZygoteWriter.flush();

            // Should there be a timeout on this?

            ProcessStartResult result = new ProcessStartResult();

            result.pid = sZygoteInputStream.readInt();

            if (result.pid < 0) {

                throw new ZygoteStartFailedEx("fork() failed");

            }

            result.usingWrapper = sZygoteInputStream.readBoolean();

            return result;

        } catch (IOException ex) {

            try {

                if (sZygoteSocket != null) {

                    sZygoteSocket.close();

                }

            } catch (IOException ex2) {

                // we're going to fail anyway

                Log.e(LOG_TAG,"I/O exception on routine close", ex2);

            }

 

            sZygoteSocket = null;

 

            throw new ZygoteStartFailedEx(ex);

        }

    }

下面对openZygoteSocketIfNeeded函数进行详细分析:

/**

     * Tries to open socket to Zygote process if not already open. If

     * already open, does nothing.  May block and retry.

     */

/*此函数尝试打开同zygote进程的socket通信*/

    private static void openZygoteSocketIfNeeded()

            throws ZygoteStartFailedEx {

        int retryCount;

        if (sPreviousZygoteOpenFailed) {

      /*如果上一次打开失败的话,就估计这一次打开也会失败,就直接返回失败状态*/

            retryCount = 0;

        } else {

            retryCount = 10;     //允许尝试10次      

        }

 

        /*

在bug#811181:某些时候runtime可能会使得本函数在zygote准备好之前就被调用,那么就肯定会失败的~这里系统暂时不做处理~~

         */

        for (int retry = 0

                ; (sZygoteSocket == null) && (retry < (retryCount + 1))

                ; retry++ ) {

            if (retry > 0) {

                try {

                    Log.i("Zygote", "Zygote not up yet, sleeping...");

                    Thread.sleep(ZYGOTE_RETRY_MILLIS); //sleep 500毫秒

                } catch (InterruptedException ex) {

                    // should never happen

                }

            }

            try {

//创建同zygote的socket链接

                sZygoteSocket = new LocalSocket();

                sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET,

                        LocalSocketAddress.Namespace.RESERVED));

            sZygoteInputStream=new DataInputStream(sZygoteSocket.getInputStream());

                sZygoteWriter =

                    new BufferedWriter(

                            new OutputStreamWriter(

                                    sZygoteSocket.getOutputStream()),

                            256);

                Log.i("Zygote", "Process: zygote socket opened");

                sPreviousZygoteOpenFailed = false;

                break;

            } catch (IOException ex) {

                if (sZygoteSocket != null) {

                    try {

                        sZygoteSocket.close();

                    } catch (IOException ex2) {

                        Log.e(LOG_TAG,"I/O exception on close after exception",

                                ex2);

                    }

                }

 

                sZygoteSocket = null;

            }

        }

        if (sZygoteSocket == null) {

            sPreviousZygoteOpenFailed = true;

            throw new ZygoteStartFailedEx("connect failed");                

        }

    }

好了,ActivityManagerService终于想zygote发送请求了~~。请求的参数中有一个字符串,它的值是“android.app.ActivityThread”。现在该回到zygote处理请求那块去看看了——就是runSelectLoop函数!

1.2 zygote接收并处理子进程的请求

在runSelectLoop函数中,一旦有来自客户端的连接,就调用zygoteConnection的runonce函数来处理客户端的连接请求,该函数的详细如下:

    boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {

        String args[];

        try {

            args = readArgumentList(); //读取SS发送过来的参数

            descriptors = mSocket.getAncillaryFileDescriptors();

        }

………

        int pid = -1;

        ……….

   //在这里zygote又分裂出了一个子进程    

pid=Zygote.forkAndSpecialize(parsedArgs.uid,parsedArgs.gid,parsedArgs.gids,

                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,

                    parsedArgs.niceName, fdsToClose);

        }

……

        try {

            if (pid == 0) {

                // 子进程处理函数

                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

                return true;

            } else {

                // in parent...pid of < 0 means failure

                IoUtils.closeQuietly(childPipeFd);

                childPipeFd = null;

                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);

            }

        }

}

接下来看看子进程处理函数handleChildProc干了些什么。具体的代码就不贴了,这里直接用文字加以描述:

①首先关闭zygote的sockets;

②然后根据传入的参数设置新进程的一些属性,因为我们传递进来的参数中有“runtime-init”所以会调用RuntimeInit.ZygoteInit函数,这个函数的功能我们已经分析过了,主要就是调用子进程类的main函数,这里就是调用android.app.ActivityThread类的main函数。实际上Android中APK程序所对应的进程就是这个类,它的main函数就是apk程序的main函数!!

③zygote子进程分裂成功后,就做一些扫尾工作,然后返回到runSelectLoop函数中继续等待请求进行下一次分裂。

所以说zygote是所有apk进程的祖先!

 

1.3 总结

这里以启动一个activity进程为例:

①ActivityManagerServer进程向zygote进程发送消息;

②zygote进程在runSelectLoop函数中接收到这个消息,fork创建子进程;

③子进程调用RuntimeInit.ZygoteInit函数,这个函数会调用子进程类的main函数,即android.app.ActivityThread的main函数,这样就启动了一个acivity进程。

posted @ 2014-05-23 21:49  WanChouchou  阅读(1205)  评论(0编辑  收藏  举报